//
//  CompGraf2ViewController.m
//  CompGraf2
//
//  Created by Juan Niosi on 02/08/11.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import <QuartzCore/QuartzCore.h>

#import "CompGraf2ViewController.h"
#import "EAGLView.h"
#import "Entity.h"
#import "Light.h"
#import "sys/time.h"
#import "Terrain.h"
#import "MD2Entity.h"
#import "Enemy.h"

// Uniform index.
enum {
    UNIFORM_TRANSLATE,
    NUM_UNIFORMS
};
GLint uniforms[NUM_UNIFORMS];

// Attribute index.
enum {
    ATTRIB_VERTEX,
    ATTRIB_COLOR,
    NUM_ATTRIBUTES
};

@interface CompGraf2ViewController ()
@property (strong, nonatomic) EAGLContext *context;
@property (retain, nonatomic) CADisplayLink *displayLink;

- (void)applicationWillResignActive:(NSNotification *)notification;
- (void)applicationDidBecomeActive:(NSNotification *)notification;
- (void)applicationWillTerminate:(NSNotification *)notification;
- (void)drawFrame;
@end

@implementation CompGraf2ViewController

@synthesize animating;
@synthesize context;
@synthesize displayLink;


- (void)viewDidLoad
{
    [super viewDidLoad];
    
    if (!self.context) {
        EAGLContext *aContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
        
        if (!aContext)
            NSLog(@"Failed to create ES context");
        else if (![EAGLContext setCurrentContext:aContext])
            NSLog(@"Failed to set ES context current");
        
        self.context = aContext;
        
        animating = NO;
        animationFrameInterval = 1;
        self.displayLink = nil;
        
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillResignActive:) name:UIApplicationWillResignActiveNotification object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillTerminateActive:) name:UIApplicationWillTerminateNotification object:nil];
        
    }

    world = [[World alloc] init];
    [(EAGLView *)self.view setContext:context];
    
    [(EAGLView *)self.view setFramebuffer];
    
    engine = [[Engine alloc] initWithView:self.view];
    
    world.camera = [[OrbitCam alloc] init:engine];
    [world.camera zoom:-2.0f];
    [world.camera rotateX:60.0f];
    [world.camera rotateY:30.0f];
    
    [engine clear];
    
    [engine update];
    
    md2Models = [[NSMutableArray alloc] init];
    
    //LOAD MODEL
    Texture *md2Tex = [engine load_texture:@"hueteotl.png"];
    MD2Model *model = [[MD2Model alloc] init:@"hueteotl"];
    [model addTexture:md2Tex];
    [md2Models addObject:model];
    
    MD2Model *model2 = [[MD2Model alloc] init:@"weapon"];
    md2Tex = [engine load_texture:@"weapon.png"];
    [model2 addTexture:md2Tex];
    [md2Models addObject:model2];
/*    
    MD2Entity *hueteotl = [[MD2Entity alloc] init:model withAnim:@"stand"];
    [hueteotl translateY:1.0f];
    [hueteotl translateZ:2.0f];
    [hueteotl scaleX:0.8f];
    [hueteotl scaleY:0.8f];
    [hueteotl scaleZ:0.8f];
*/    
    MD2Entity *weapon = [[MD2Entity alloc] init:model2 withAnim:@"stand"];
//    [hueteotl addChild:weapon];
    
    //[entities addObject:hueteotl];
    
    //load terrain
    world.terrain = [[Terrain alloc] init:@"terrain.txt" engine:engine];
    //[entities addObject:terrain];
    
    MapNode *start = [[MapNode alloc] initWithCoords:0 :0];
    MapNode *end = [[MapNode alloc] initWithCoords:13 :15];
    
    Enemy *e1 = [[Enemy alloc] init:model withWalkSpeed:3.6f withTurnSpeed:280.0f startsAt:end views:10.0f];
    [e1 translateY:1.0f];
    [world addEnemy:e1];
    
//    [hueteotl setPosition:[terrain posToCoords:0 :0]];
    world.mainCharacter  = [[CharacterController alloc] init:model withWalkSpeed:3.6f withTurnSpeed:280.0f :start];
    [world.mainCharacter addChild:weapon];
    [world.mainCharacter setPosition:[world.terrain posToCoords:0 :0]];
    [world.mainCharacter translateY:1.0f];
    NSLog(@"%s", glGetString(GL_VERSION));

    //create light
    GLfloat *lightPos1 = malloc(sizeof(GLfloat)*4);
    lightPos1[0] = 0.0f;
    lightPos1[1] = 10.0f;
    lightPos1[2] = 0.0f;
    lightPos1[3] = 1.0f;
    
    GLfloat *ambient1 = malloc(sizeof(GLfloat)*4);
    ambient1[0] = 0.3f;
    ambient1[1] = 0.3f;
    ambient1[2] = 0.3f;
    ambient1[3] = 1.0f;

    GLfloat *diffuse1 = malloc(sizeof(GLfloat)*4);
    diffuse1[0] = 1.0f;
    diffuse1[1] = 1.0f;
    diffuse1[2] = 1.0f;
    diffuse1[3] = 1.0f;
    
    GLfloat *specular1 = malloc(sizeof(GLfloat)*4);
    specular1[0] = 1.0f;
    specular1[1] = 1.0f;
    specular1[2] = 1.0f;
    specular1[3] = 1.0f;
    
    Light *l1 = [[Light alloc] initSpot:GL_LIGHT0 setAngle:60.0f];
    [l1 setLightPos:lightPos1];
    [l1 setAmbient:ambient1];
    [l1 setDiffuse:diffuse1];
    [l1 setSpecular:specular1];
    [l1 setAttenuation:0.01f];
    [l1 setSpotExp:5.0f];
    

    NSLog(@"Light Pos %i %i %f %f %f", 0, 0, l1.position[0], l1.position[1], l1.position[2]);
    
    //attach light
    [world.lights addObject:l1];
    
    /*  
    NSLog(@"VENDOR %s", glGetString(GL_VENDOR));
    NSLog(@"RENDERER %s", glGetString(GL_RENDERER));
    NSLog(@"SHADING LANGUAGE VERSION %s", glGetString(GL_SHADING_LANGUAGE_VERSION));
    NSLog(@"EXTENSIONS %s", glGetString(GL_EXTENSIONS));
     */
    
    //Add gesture recognizers
    panGR = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(onMove:)];
    [panGR setMinimumNumberOfTouches:1];
    [panGR setMaximumNumberOfTouches:1];
    [panGR setDelegate:self];
    [self.view addGestureRecognizer:panGR];
    
    pinchGR = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(onPinch:)];
    [pinchGR setDelegate:self];
    [self.view addGestureRecognizer:pinchGR];
    
    tapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTap:)];
    [tapGR setNumberOfTapsRequired:1];
    //[tapGR setNumberOfTouchesRequired:1];
    [tapGR setDelegate:self];
    [self.view addGestureRecognizer:tapGR];

    [self drawFrame];
}

- (void)onTap:(UITapGestureRecognizer *)sender
{
        
    CGPoint pos2D =[sender locationInView:self.view];

    //Resolver giro de pantalla
    if (self.interfaceOrientation == UIInterfaceOrientationLandscapeLeft || self.interfaceOrientation == UIInterfaceOrientationLandscapeRight)
    {
        pos2D.x = pos2D.x / self.view.bounds.size.width * self.view.bounds.size.height;
        pos2D.y = pos2D.y / self.view.bounds.size.height * self.view.bounds.size.width;
    }
    //NSLog(@"pos2D %f %f\n",pos2D.x, pos2D.y);
        
    [world worldClic:pos2D];
}

-(void)onMove:(UIPanGestureRecognizer *)sender
{
    
    if ([sender state] == UIGestureRecognizerStateBegan || [sender state] == UIGestureRecognizerStateChanged) 
    {
        
        CGPoint translation = [sender translationInView:self.view];
     
        GLfloat *rot= malloc(sizeof(GLfloat)*3);
        rot[0] = translation.y * 0.01f;
        rot[1] = translation.x * 0.01f;
        rot[2] = 0.0f;
        
        [world.camera rotate:rot];
        
        free(rot);
    }
}

-(void)onMove2:(UIPanGestureRecognizer *)sender
{
    
    if ([sender state] == UIGestureRecognizerStateBegan || [sender state] == UIGestureRecognizerStateChanged) 
    {
        
        CGPoint translation = [sender translationInView:self.view];
        
        GLfloat *mov= malloc(sizeof(GLfloat)*3);
        mov[0] = -translation.x * 0.001f;
        mov[1] = 0.0f;
        mov[2] = -translation.y * 0.001f;
        
        [world.camera translate:mov];
        free(mov);
    }
}

- (void)onPinch:(UIPinchGestureRecognizer *)sender
{
    if ([sender state] == UIGestureRecognizerStateBegan)
        lastScale = [(UIPinchGestureRecognizer*)sender scale];
    
    CGFloat scale = lastScale - [(UIPinchGestureRecognizer*)sender scale];
    scale *= -4.0f;
    
    lastScale = [(UIPinchGestureRecognizer*)sender scale];
    
    [world.camera zoom:scale];
}

- (void)applicationWillResignActive:(NSNotification *)notification
{
    if ([self isViewLoaded] && self.view.window) {
        [self stopAnimation];
    }
}

- (void)applicationDidBecomeActive:(NSNotification *)notification
{
    if ([self isViewLoaded] && self.view.window) {
        [self startAnimation];
    }
}

- (void)applicationWillTerminate:(NSNotification *)notification
{
    if ([self isViewLoaded] && self.view.window) {
        [self stopAnimation];
    }
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    if (program) {
        glDeleteProgram(program);
        program = 0;
    }
    
    // Tear down context.
    if ([EAGLContext currentContext] == context)
        [EAGLContext setCurrentContext:nil];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Release any cached data, images, etc. that aren't in use.
}

- (void)viewWillAppear:(BOOL)animated
{
    [self startAnimation];
    
    [super viewWillAppear:animated];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [self stopAnimation];
    
    [super viewWillDisappear:animated];
}

- (void)viewDidUnload
{
	[super viewDidUnload];
	
    if (program) {
        glDeleteProgram(program);
        program = 0;
    }
    
    // Tear down context.
    if ([EAGLContext currentContext] == context)
        [EAGLContext setCurrentContext:nil];
	self.context = nil;	
}

- (NSInteger)animationFrameInterval
{
    return animationFrameInterval;
}

- (void)setAnimationFrameInterval:(NSInteger)frameInterval
{
    /*
	 Frame interval defines how many display frames must pass between each time the display link fires.
	 The display link will only fire 30 times a second when the frame internal is two on a display that refreshes 60 times a second. The default frame interval setting of one will fire 60 times a second when the display refreshes at 60 times a second. A frame interval setting of less than one results in undefined behavior.
	 */
    if (frameInterval >= 1) {
        animationFrameInterval = frameInterval;
        
        if (animating) {
            [self stopAnimation];
            [self startAnimation];
        }
    }
}

- (void)startAnimation
{
    if (!animating) {
        CADisplayLink *aDisplayLink = [[UIScreen mainScreen] displayLinkWithTarget:self selector:@selector(drawFrame)];
        [aDisplayLink setFrameInterval:animationFrameInterval];
        [aDisplayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        self.displayLink = aDisplayLink;
        
        animating = YES;
    }
}

- (void)stopAnimation
{
    if (animating) {
        [self.displayLink invalidate];
        self.displayLink = nil;
        animating = NO;
    }
}

- (void)drawFrame
{
    [engine clear];
    
    //Set camera transformations
    [world.camera drawPos:engine];
    
    //Updates
    
    [world.mainCharacter update:engine.lastUpdateDelta];
    
    world.camera.position[0] = -world.mainCharacter.position[0];
    world.camera.position[2] = -world.mainCharacter.position[2];
    
    for (Light* l in world.lights)
    {
        [l update:engine.lastUpdateDelta];
    }
    
    Entity *ent;
    for (ent in world.entities)
    {
        [ent update:engine.lastUpdateDelta];
    }

    Enemy *enm;
    for (enm in world.enemies)
    {
        [enm update:engine.lastUpdateDelta];
    }
    
    //Draw Lights
    for (Light* l in world.lights)
    {
        [l draw:engine :world.camera];
    }
    
    //Draw char
    [world.mainCharacter draw:engine :world.camera];
    
    //Draw terrain
    [world.terrain draw:engine :world.camera];
    if (world.path != NULL)
        [world.terrain drawPath:world.path withEngine:engine];
    
    //Draw entities
    for (ent in world.entities)
    {
        [ent draw:engine :world.camera];
    }
    
    //Draw enemies
    for (enm in world.enemies)
    {
        [enm draw:engine:world.camera];
    }
    
    //Reset
    [world.camera reset:engine];
    [engine update];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
    [engine updateViewport:toInterfaceOrientation];
    return (toInterfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
@end
